package com.coderman.common.starter.nacos.datadict.service;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.coderman.common.starter.nacos.datadict.config.NacosDataProperties;
import com.coderman.common.starter.nacos.datadict.data.StrictList;
import com.coderman.common.starter.nacos.datadict.data.StrictMap;
import com.coderman.utils.kvpair.KVPair;
import com.coderman.utils.kvpair.KVParentPair;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

@Service
public class NacosDataServiceImpl implements DataService{
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private NacosDataProperties nacosDataProperties;

    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;


    private ConcurrentHashMap<String, Map<String,StrictMap<String>>> kvEnumMap = new ConcurrentHashMap();

    /**
     * k:nacos中的group_id
     * v:nacos中group_id 对应的数据ListKVPair
     */
    private ConcurrentHashMap<String, Map<String,StrictList<KVPair>>> kvPairMap = new ConcurrentHashMap();

    /**
     * k:nacos中的group_id
     * v:nacos中group_id 对应的数据ListKVPair
     */
    private ConcurrentHashMap<String, Map<String,List<KVParentPair<String,String,String>>>> kvParentPairMap = new ConcurrentHashMap();
    /**
     * 通过原生Java方式获取ConfigService
     * @return
     * @throws NacosException
     */
    private ConfigService getConfigService() throws NacosException {
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, nacosDiscoveryProperties.getServerAddr());
        return NacosFactory.createConfigService(properties);
    }

    @Override
    public void addListener() throws NacosException {
        Map<String,String> dataIDMap = new HashMap<>();
        ConfigService configService = getConfigService();
        String [] dataIDArr = nacosDataProperties.getDataIDArr();

        if(dataIDArr != null && dataIDArr.length > 0){
            for (int i = 0;i < dataIDArr.length; i++){
                dataIDMap.put(i+"", dataIDArr[i]);
            }
        }
        String [] groupIDArr = nacosDataProperties.getGroupIDArr();

        if(groupIDArr == null  || groupIDArr.length == 0){
            logger.warn("nacos data not fund groupIdArr ,please check your config application-nacosdatadict.yml");
            return;
        }

        for (String str : groupIDArr){
            String [] strArr = str.split("-");
            String dataID = dataIDMap.get(strArr[0]);
            if(StringUtils.isNotEmpty(dataID)){
                convertNacosData(dataID,strArr[1],configService);
                addListener(dataID,strArr[1],configService);
            }
        }
    }

    /**
     * 针对不同的dataid,groupid添加listener
     * @param dataId
     * @param groupID
     * @throws NacosException
     */
    private void addListener(final String dataId, final String groupID, ConfigService configService) throws NacosException {

        configService.addListener(dataId, groupID, new Listener() {
            @Override
            public void receiveConfigInfo(String configInfo) {
                exeConvert(configInfo,dataId,groupID);
            }

            @Override
            public Executor getExecutor() {
                return null;
            }
        });
    }

    @Override
    public Map<String,StrictMap<String>> getDataMap(String dataID, String ... groupIDArr) {
        Map<String,StrictMap<String>> dataMap = new HashMap<>();
        Map<String,StrictMap<String>> AllDataMap = kvEnumMap.get(dataID);
        for (String groupId : groupIDArr){
            StrictMap<String> strictMap = AllDataMap.get(groupId);
            if(strictMap != null){
                dataMap.put(groupId,strictMap);
            }
        }
        return dataMap;
    }

    @Override
    public Map<String,StrictList<KVPair>> getDataKVList(String dataID, String ... groupID) {
        Map<String,StrictList<KVPair>> map = new HashMap<>();
        Map<String,StrictList<KVPair>> AllDataMap = kvPairMap.get(dataID);
        String [] groupIDArr = nacosDataProperties.getGroupIDArr();

        for (String groupId : groupIDArr){
            StrictList<KVPair> list = AllDataMap.get(groupId);
            if(list != null){
                map.put(groupId,list);
            }
        }
        return map;
    }

    /**
     * 解析配置内容
     * @param dataID
     * @param groupID
     * @throws NacosException nacos异常
     */
    private void convertNacosData(String dataID, String groupID, ConfigService configService) throws NacosException {
        String content = configService.getConfig(dataID, groupID, 3000);
        exeConvert(content,dataID,groupID);
    }

    private void exeConvert(String content,String dataID,String groupID){
        String[] array = content.split("\n");
        StrictMap dataStrictMap = new StrictMap<>(array[0]);
        StrictList dataStrictList = new StrictList<>(array[0]);
        StrictList dataStrictKVPList = new StrictList<>(array[0]);

        for (int i = 1; i < array.length; i++) {
            String[] kvArr = array[i].replace(" ", "").replace("\r", "").split(",");
            if(kvArr.length == 3){
                dataStrictKVPList.add(new KVParentPair<>(kvArr[1], kvArr[0], kvArr[2]));
            }
            else if(kvArr.length == 2){
                dataStrictMap.put(kvArr[1], kvArr[0]);
                dataStrictList.add(new KVPair<>(kvArr[1], kvArr[0]));
            }
        }
        if(!dataStrictMap.isEmpty()){
            Map<String,StrictMap<String>> mapMap = new HashMap<>();
            mapMap.put(groupID, dataStrictMap);
            kvEnumMap.put(dataID,mapMap);
        }
        if(!dataStrictList.isEmpty()){
            Map<String,StrictList<KVPair>> map = new HashMap<>();
            map.put(dataID, dataStrictList);
            kvPairMap.put(groupID,map);
        }
        if(!dataStrictKVPList.isEmpty()){
            Map<String,List<KVParentPair<String,String,String>>> map = new HashMap<>();
            map.put(dataID, dataStrictKVPList);
            kvParentPairMap.put(groupID, map);
        }
        logger.info(array[0] + " has data changed,dataId={},groupID={}......................................",dataID,groupID);
    }
}
